package com.xdap.water.service;

import com.alibaba.fastjson.JSON;
import com.definesys.mpaas.common.exception.MpaasBusinessException;
import com.xdap.water.config.QueryType;
import com.xdap.water.dao.WaterDao;
import com.xdap.water.pojo.*;
import com.xdap.water.util.StringUtil;
import com.xdap.water.vo.WaterCardInfoVo;
import com.xdap.water.vo.WaterSearchParamVo;
import com.xdap.water.vo.WaterTrapeziumItemVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class WaterService {
    private final WaterDao waterDao;

    public List<ProjectTypePojo> queryAllProjectType() {
        return waterDao.queryAllProjectType();
    }

    public Map<String, Object> queryProjectByParams(WaterSearchParamVo vo) {
        List<ProjectItemPojo> projectList = waterDao.queryProjectByParams(vo);
        List<InvestmentPhasePojo> phaseList = waterDao.queryPhaseByTopPhase(null);
        List<ProjectReservePojo> reserveList = waterDao.queryProjectReserveByParams(vo);

        log.info("projectList => {}", projectList);
        log.info("phaseList => {}", phaseList);
        log.info("reserveList => {}", reserveList);

        WaterCardInfoVo info = new WaterCardInfoVo(projectList, phaseList, reserveList);

        return info.calculate();
    }

    public List<WaterTrapeziumItemVo> queryTrapeziumInfo(WaterSearchParamVo vo) {
        List<ProjectItemPojo> projectList = waterDao.queryProjectByParams(vo);
        List<InvestmentPhasePojo> phaseList = waterDao.queryPhaseByTopPhase(vo.getTopPhase());

        log.info("projectList => {}", projectList);
        log.info("phaseList => {}", phaseList);

        WaterCardInfoVo info = new WaterCardInfoVo(projectList, phaseList, new ArrayList<>());

        return info.getTrapeziumList();
    }

    public List<String> queryResponsibleUnit() {
        List<ProjectItemPojo> projectList = waterDao.queryProjectByParams(new WaterSearchParamVo());
        Set<String> set = new HashSet<>();
        for (ProjectItemPojo project : projectList) {
            String responsibleUnit = project.getResponsibleUnit();
            if (StringUtils.isNotBlank(responsibleUnit)) {
                set.add(responsibleUnit);
            }
        }
        // 添加全部
        set.add("all");
        return new ArrayList<>(set);
    }

    public String queryMinYear() {
        WaterProjectYearTaskPojo year = waterDao.queryMinYear();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        return sdf.format(year.getYear());
    }

    public List<GtProjectXmlPojo> queryProjectType() {
        return waterDao.queryProjectType();
    }

    public List<GtProjectUnitPojo> queryAllUnit() {
        return waterDao.queryAllUnit();
    }

    public List<WaterProjectYearTaskPojo> queryCurrentYearProjectYearTask() {
        List<WaterProjectYearTaskPojo> currentYearProjectYearTasks = waterDao.queryCurrentYearProjectYearTask();

        for (WaterProjectYearTaskPojo currentYearProjectYearTask : currentYearProjectYearTasks) {
            String projectType = currentYearProjectYearTask.getProjectType();
            String unit = currentYearProjectYearTask.getUnit();
            if (StringUtils.isNotBlank(projectType)) {
                List<String> projectIds = JSON.parseArray(projectType, String.class);
                if (projectIds.size() > 0) {
                    currentYearProjectYearTask.setProjectTypeId(projectIds.get(0));
                }
            }
            if (StringUtils.isNotBlank(unit)) {
                List<String> unitIds = JSON.parseArray(unit, String.class);
                if (unitIds.size() > 0) {
                    currentYearProjectYearTask.setUnitId(unitIds.get(0));
                }
            }
        }

        return currentYearProjectYearTasks;
    }

    public GtFixedInvestCompleteStatusPojo queryCompleteStatusByDate(String date) {
        if (StringUtils.isNotBlank(date)) {
            GtFixedInvestCompleteStatusPojo data = waterDao.queryFixedInvestCompleteStatus(date);
            if (null != data) {
                data.setUnitCompleteStatusPojoList(waterDao.queryUnitCompleteStatusListByTabDocId(data.getDocumentId()));
            }
            return data;
        } else {
            throw new MpaasBusinessException("非法参数");
        }
    }

    public String queryMaxDate() {
        GtFixedInvestCompleteStatusPojo data = waterDao.queryMaxDate();

        if (null != data) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.format(data.getFillDate());
        }
        return null;
    }

    public List<WaterProjectYearTaskPojo> queryUnitChartData(String unit, String date) {
        SimpleDateFormat dateTimeSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat yearSdf = new SimpleDateFormat("yyyy");

        log.info("传入参数 unit -> {}", unit);
        log.info("传入参数 date -> {}", date);

        date += "-09 00:00:00";
        Date d;

        try {
            d = dateTimeSdf.parse(date);
        } catch (ParseException e) {
            throw new MpaasBusinessException("时间解析异常");
        }

        String year = yearSdf.format(d);

        List<WaterProjectYearTaskPojo> projects = waterDao.queryWaterProjectByYearAndUnit(unit, year);
        log.info("projects -> size -> {}", projects.size());
        if (projects.size() > 0) {
            List<String> projectIdsWithBracket = new ArrayList<>();
            List<String> projectIdsWithoutBracket = new ArrayList<>();

            for (WaterProjectYearTaskPojo project : projects) {
                projectIdsWithBracket.add(String.format("'%s'", project.getProjectName()));
                projectIdsWithoutBracket.add(StringUtil.removeBracket(project.getProjectName()));
            }
            List<GtProjectInformationPojo> projectInformationList = waterDao.queryProjectInformationListById(projectIdsWithoutBracket);
            String end = getNextFormatDate(d);
            String start = year + "-01-09 00:00:00";
            List<GtFillProjectPojo> fillProjectList = waterDao.queryFillProjectByMaxDate(projectIdsWithBracket, start, end);

            Map<String, GtProjectInformationPojo> infoMap = new HashMap<>();
            Map<String, GtFillProjectPojo> fillMap = new HashMap<>();

            for (GtProjectInformationPojo info : projectInformationList) {
                infoMap.put(StringUtil.addBracket(info.getId()), info);
            }

            for (GtFillProjectPojo fill : fillProjectList) {
                fillMap.put(fill.getProjectName(), fill);
            }

            for (WaterProjectYearTaskPojo project : projects) {
                String key = project.getProjectName();
                project.setFillProject(fillMap.get(key));
                project.setProjectInformation(infoMap.get(key));
            }
        }

        return projects;
    }

    public List<Double> queryPlanInvestSchedule(String unit, String year) {
        getFullYearNumber(year);
        Double[] invests = getPlanAmounts(unit, year);

        for (int i = 0; i < invests.length; i++) {
            log.info("{}月份计划投资 => {}", i + 1, invests[i]);
            if (i != 0) {
                log.info("------------------------------------------");
                log.info("{}月份计划投资 => {} - ***", i, invests[i - 1]);
                invests[i] += invests[i - 1];
                log.info("{}月份计划投资 => {} - ***", i + 1, invests[i]);
                log.info("------------------------------------------");
            }
        }

        return Arrays.asList(invests);
    }

    public List<Double> queryActualInvestSchedule(String unit, String year) {
        int fullYear = getFullYearNumber(year);
        List<GtFillProjectPojo> fillProjectList = getFillProjectList(unit, fullYear);
        Map<String, Double[]> projectAmountMap = getProjectAmountMap(fillProjectList, fullYear, QueryType.INVEST);
        Double[] investList = getTotalAmount(projectAmountMap);
        printInvestInfo("占位符", investList);
        return Arrays.asList(generateNoZeroArray(investList));
    }

    public List<Double> queryPlanNtSchedule(String unit, String year) {
        getFullYearNumber(year);
        Double[] invests = getPlanAmounts(unit, year);
        return Arrays.asList(invests);
    }

    public List<Double> queryActualNtSchedule(String unit, String year) {
        int fullYear = getFullYearNumber(year);
        List<GtFillProjectPojo> fillProjectList = getFillProjectList(unit, fullYear);
        Map<String, Double[]> projectAmountMap = getProjectAmountMap(fillProjectList, fullYear, QueryType.NT);
        Double[] ntList = getTotalAmount(projectAmountMap);
        printInvestInfo("占位符 --- 剔除前", ntList);
        // 先剔除为0的数据
        ntList = generateNoZeroArray(ntList);
        printInvestInfo("占位符 --- 剔除后", ntList);
        Double[] nts = new Double[ntList.length];
        // 这里不能直接改变ntList的值 因为业务逻辑
        for (int i = 0; i < ntList.length; i++) {
            if (i == 0) {
                nts[i] = ntList[i];
            } else {
                nts[i] = ntList[i] - ntList[i - 1];
            }
        }
        printInvestInfo("占位符 --- 计算完成", nts);
        // 是否考虑剔除 < 0 的数据
        return Arrays.asList(nts);
    }

    public Double queryCurrentYearNtTask(String unit, String year) {
        getFullYearNumber(year);
        List<WaterProjectYearTaskPojo> projectYearTaskList = null;
        if (StringUtils.isNotBlank(unit)) {
            List<String> projectIds = queryProjectIdByUnit(unit);
            projectYearTaskList = waterDao.queryProjectYearTaskByYearAndIds(year, projectIds);
        } else {
            projectYearTaskList = waterDao.queryWaterProjectByYearAndUnit(null, year);
        }
        Double amount = 0.0;
        log.info("size => {}", projectYearTaskList.size());
        for (WaterProjectYearTaskPojo p : projectYearTaskList) {
            Double tempAmount = p.getYearInvestmentTask();
            log.info("tempAmount => {}", tempAmount);
            amount += ((null == tempAmount) ? 0 : tempAmount);
        }
        return amount;
    }

    private String getNextFormatDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);

        return String.format("%s-%s-08 23:59:59", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
    }

    private int getMonthByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        return calendar.get(Calendar.MONTH);
    }

    private int getFullYearNumber(String year) {
        if (StringUtils.isBlank(year)) {
            log.error("年份参数为空");
            throw new MpaasBusinessException("非法参数");
        }

        int fullYear = 0;
        try {
            fullYear = Integer.parseInt(year);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            log.error("年份参数格式错误");
            throw new MpaasBusinessException("非法参数");
        }

        return fullYear;
    }

    private List<String> queryProjectIdByUnit(String unit) {
        List<GtProjectInformationPojo> projectInfoList = waterDao.queryProjectInformationListByUnitId(String.format("[\"%s\"]", unit));
        List<String> projectIds = projectInfoList.stream().map(GtProjectInformationPojo::generateSpecialIdStr).collect(Collectors.toList());
        log.info("项目ID集合 => {}", projectIds);
        return projectIds;
    }

    private int getMonthByDate(Date date, int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        if (calendar.get(Calendar.YEAR) != year) {
            // 那就是12月
            return 11;
        } else {
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            int month = calendar.get(Calendar.MONTH);
            if (day > 8) {
                return month;
            } else {
                if (month - 1 < 0) {
                    log.error("查询sql出错，出现了1月8号之前的数据");
                    throw new MpaasBusinessException("参数错误");
                }
                return month - 1;
            }
        }
    }

    private Double[] generateAmountListByFillProjects(List<GtFillProjectPojo> fillProjects, int year, QueryType type) {
        Double[] invests = new Double[12];
        Arrays.fill(invests, 0.0);
        for (GtFillProjectPojo p : fillProjects) {
            int index = getMonthByDate(p.getFillDate(), year);
            if (0.0 == invests[index]) {
                switch (type) {
                    case NT:
                        invests[index] = p.getCurrentTotalInvertAmount();
                        break;
                    case INVEST:
                        invests[index] = p.getCurrentInvertAmount();
                        break;
                }
            }
        }
        return invests;
    }

    private void printInvestInfo(String projectId, Double[] invests) {
        log.info("------------------------------ 项目ID {} start------------------------------", projectId);
        for (int i = 0; i < invests.length; i++) {
            log.info("{}月份投资金额 -> {}", i + 1, invests[i]);
        }
        log.info("------------------------------ 项目ID {} end ------------------------------\n\n\n", projectId);
    }

    private Double[] generateNoZeroArray(Double[] array) {
        int index = array.length -1;
        while(array[index] == 0.0) {
            index--;
        }
        int newLength = index + 1;
        Double[] newArray = new Double[newLength];

        for (int i = 0; i < newLength; i++) {
            newArray[i] = array[i];
        }

        return newArray;
    }

    private List<GtFillProjectPojo> getFillProjectList(String unit, int year) {
        List<GtFillProjectPojo> fillProjectList = null;
        String start = String.format("%s-01-09 00:00:00", year);
        String end = String.format("%s-01-08 23:59:59", year + 1);

        if (StringUtils.isNotBlank(unit)) {
            List<String> projectIds = queryProjectIdByUnit(unit);
            fillProjectList = waterDao.queryFillProject(start, end, projectIds);
        } else {
            fillProjectList = waterDao.queryFillProject(start, end);
        }

        return fillProjectList;
    }

    private Map<String, Double[]> getProjectAmountMap(List<GtFillProjectPojo> fillProjectList, int year, QueryType type) {
        // 按照项目名称进行分组
        Map<String, List<GtFillProjectPojo>> projectNameMap = fillProjectList.stream().collect(Collectors.groupingBy(GtFillProjectPojo::getProjectName));
        Map<String, Double[]> projectAmountMap = new HashMap<>();
        projectNameMap.forEach((projectId, fillProjects) -> {
            // 日期降序排列
            Collections.sort(fillProjects, (p1, p2) -> p2.getFillDate().compareTo(p1.getFillDate()));
            Double[] invests = generateAmountListByFillProjects(fillProjects, year, type);
            printInvestInfo(projectId, invests);
            projectAmountMap.put(projectId, invests);
        });

        return projectAmountMap;
    }

    private Double[] getTotalAmount(Map<String, Double[]> projectAmountMap) {
        Double[] investList = new Double[12];
        Arrays.fill(investList, 0.0);

        projectAmountMap.forEach((projectId, invests) -> {
            for (int i = 0; i < invests.length; i++) {
                investList[i] += invests[i];
            }
        });

        return investList;
    }

    private Double[] getPlanAmounts(String unit, String year) {
        List<GtProjectInvestSchedulePojo> projectInvestList = null;

        if (StringUtils.isNotBlank(unit)) {
            List<String> projectIds = queryProjectIdByUnit(unit);
            projectInvestList = waterDao.queryProjectInvestSchedule(year, projectIds);
        } else {
            projectInvestList = waterDao.queryProjectInvestSchedule(year);
        }

        Double[] invests = new Double[12];
        Arrays.fill(invests, 0.0);

        for (GtProjectInvestSchedulePojo projectInvest : projectInvestList) {
            int index = getMonthByDate(projectInvest.getYearMonth());
            invests[index] += projectInvest.getSingleMonthPlanInvestAmount();
        }

        return invests;
    }
}
